import axios from 'axios'
import qs from 'qs'

import { isObject } from '.'
import { SERVER_ERROR_MESSAGE } from './common'

const defalutConfig = {
    // 响应超时时长
    timeout: 30000,
}

const instance = axios.create(defalutConfig)

/**
 * 获取token
 * @returns
 */
function getToken() {
    const token = 'xxxx'
    // 从redux或storage或cookie里获取token
    // token一般都是有有效期的，大多数服务器都会对登陆用户进行心跳检测，一般是1小时左右，有的会更长
    // 如果在有效期内有新的请求发起，那么这个token的有效期会顺延；如果在有效期结束之前一直没有新的请求
    // 则token失效，用户需要重新登陆
    return 'Bearer ' + token
}
// 请求拦截
instance.interceptors.request.use(
    config => {
        // 请求拦截，我们可以在这里拦截到请求并对config进行配置，比如header
        console.log('这是请求发起之前', config)

        // 判断是否有全局的loading设置
        if (config.showLoading) {
            // 调用antd的loading
        }

        // 返回设定的一些配置
        return {
            // 保持原来的配置不受影响
            ...config,
            ...{
                headers: {
                    // token,一般用来发送给接口判断用户是否已获取相关权限
                    // 广义来说，webapp有两种用户，一种为游客，一种为注册用户
                    // 注册用户会再根据他的权限细分为拥有各种权限的用户组
                    // 'access-token': getToken(config.url),
                    'Authori-zation': getToken(),
                    // content-type 一般用于告知接口，我们需要用什么样的方式来获取数据，如果这个属性不正确可能会出现一些意想不到的结果
                    // 比如明明是获取一段数据，接口可能会返回一个文件地址让你下载
                    // 如果是下载文件，这里我们需要改成：application/octet-stream
                    // 如果是上传文件，这里我们需要改成：multipart/form-data
                    // 更多配置类型可以参考 https://www.runoob.com/http/http-content-type.html
                    // 默认格式：以key:value格式发送数据到服务器（也是表单的默认提交格式）
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
            },
        }
    },
    error => {
        // 请求出错了，可以在这里打印error看看是什么问题
        console.log('发起请求时报错了', error)
        // 返回错误信息给调用者
        return Promise.reject(error)
    }
)

function checkErrorMessage(code) {
    return SERVER_ERROR_MESSAGE['_' + code] || '网络问题暂时无法访问，请稍后再试'
}
// 响应拦截器
instance.interceptors.response.use(
    response => {
        // 响应拦截，我们可以在这里拦截到服务器响应
        console.log('服务器正确响应了', response)
        // 判断是否有全局的loading设置
        if (response?.config.showLoading) {
            // 隐藏antd的loading
        }
        // 如果返回的状态码为200，说明接口请求成功，可以正常拿到数据，为了减少调用方的代码，
        // 我们在这里只返回reaponse中的data部分，也就是我们的api返回的内容
        // 甚至我们还可以通过传入一些配置参数，在这里对一些特定的api状态码进行统一处理，更进一步地减少调用方的代码
        if (response.status === 200 && response.data?.status === 200) {
            return response.data
        }
        // 返回服务器的错误
        return Promise.reject(checkErrorMessage(response.status))
    },
    // 服务器返回非2开头状态码的情况
    error => {
        // 服务器返回错误，可以在这打印错误是什么
        console.log('服务器返回错误了', error)
        //
    }
)

function request(url, method, data) {
    return new Promise((resolve, reject) => {
        return instance[method](
            url,
            method === 'get' || method === 'delete' ? data : isObject(data) ? qs.stringify(data) : data
        ).then(res => {
            resolve(res)
        })
    })
}

/**
 * 向外抛出的简易方法，可以有效减少固定格式的请求参数传递
 * @param {*} url
 * @param {*} data
 * @returns
 */
export function post(url, data) {
    return request(url, 'post', data)
}
export function put(url, data) {
    return request(url, 'put', data)
}
export function get(url, data) {
    return request(url, 'get', data)
}
export function del(url, data) {
    return request(url, 'delete', data)
}

export default instance
